package com.hhkj.admin.question.common.utils;

import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.hhkj.admin.question.common.cont.QuestionFormatConst;
import com.hhkj.admin.question.common.cont.QuestionImportConst;
import com.hhkj.admin.question.common.cont.QuestionTypeEnum;
import com.hhkj.admin.question.domain.Question;
import com.hhkj.admin.question.model.extend.Option;
import com.hhkj.admin.question.model.extend.QuestionExportModel;
import com.hhkj.admin.question.model.extend.QuestionImportModel;
import com.hhkj.admin.question.model.req.ExcelTypeCountReq;
import com.hhkj.admin.question.model.req.QuestionReq;
import com.ruoyi.common.cont.SysConst;
import com.ruoyi.common.exception.GlobalErrorListException;
import com.ruoyi.common.exception.GlobalException;
import com.ruoyi.common.model.excel.ExcelImportError;
import com.ruoyi.common.utils.excl.ExcelImportDataUtils;
import com.ruoyi.common.utils.excl.utils.ExcelUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.*;

/**
 * QuestionImportUtils
 *
 * @author HHKJ-SERVER-ZJ
 * @since 2023/5/17 16:43
 */
public class QuestionImportUtils {

    /**
     * 读取导入模板题目列表
     *
     * @param req 请求信息
     * @return 题目模板列表
     */
    public static List<QuestionReq> readExcelQuestionList(ExcelTypeCountReq req) {
        List<QuestionImportModel> modelList;
        if (ObjectUtil.isNotNull(req.getFile())) {
            modelList = QuestionImportUtils.readModelList(req.getFile());
        } else if (StrUtil.isNotBlank(req.getFileUrl())) {
            modelList = QuestionImportUtils.readModelList(req.getFileUrl());
        } else {
            throw new GlobalException("参数错误！请联系管理员！");
        }

        return QuestionImportUtils.convertGroupListImportModelList(modelList);
    }

    /**
     * 读取导入模板题目列表
     *
     * @param fileUrl 文件url地址
     * @return 题目模板列表
     */
    public static List<QuestionImportModel> readModelList(String fileUrl) {
        // MultipartFile multipartFile = new MultipartFile();
        try {
            File file = File.createTempFile(UUID.randomUUID().toString(), "xlsx");
            HttpUtil.downloadFileFromUrl(fileUrl, file);
            //
            InputStream inputStream = Files.newInputStream(file.toPath());
            return readModelList(inputStream);
        } catch (IOException e) {
            throw new GlobalException("文件读取失败！");
        }
    }

    /**
     * 读取导入模板题目列表
     *
     * @param inputstream 文件流
     * @return 题目模板列表
     */
    public static List<QuestionImportModel> readModelList(InputStream inputstream) {
        return ExcelUtils.importExcel(inputstream, QuestionImportModel.class, 2);
    }

    /**
     * 读取导入模板题目列表
     *
     * @param file 用户上传文件
     * @return 题目模板列表
     */
    public static List<QuestionImportModel> readModelList(MultipartFile file) {
        try {
            return ExcelUtils.importExcel(file.getInputStream(), QuestionImportModel.class, 2);
        } catch (IOException e) {
            throw new GlobalException("文件读取失败！");
        }
    }

    /**
     * 批量读取
     *
     * @param file 文件
     * @return 题目列表分组
     */
    public static Map<String, List<QuestionImportModel>> readMultipleModelListGroupByTypeCode(MultipartFile file) {
        ImportParams importParams = new ImportParams();
        importParams.setKeyIndex(2);
        return ExcelUtils.importExcelMultiple(file, QuestionImportModel.class, importParams);
    }

    /**
     * 题目列表信息转换
     *
     * @param modelList 题目列表信息
     * @return 题目列表
     */
    public static List<QuestionReq> convertGroupListImportModelList(List<QuestionImportModel> modelList) {

        List<ExcelImportError<QuestionImportModel>> errorList = new ArrayList<>();
        List<QuestionReq> questionList = convertGroupListImportModelList(modelList, "sheet1", errorList);
        // 又不符合格式的信息，抛出异常
        if (CollectionUtil.isNotEmpty(errorList)) {
            throw new GlobalErrorListException(errorList);
        }
        return questionList;
    }

    /**
     * 题目导入列表
     *
     * @param modelList  题目列表
     * @param courseName 课程名称
     * @param errorList  错误信息列表
     * @return 题目列表信息
     */
    public static List<QuestionReq> convertGroupListImportModelList(List<QuestionImportModel> modelList,
                                                                    String courseName,
                                                                    List<ExcelImportError<QuestionImportModel>> errorList) {
        List<String> errorMessageList;
        List<QuestionReq> questionList = new ArrayList<>();
        QuestionReq caseQuestion = null;
        QuestionReq question;
        // 检查题目信息
        ExcelImportDataUtils.initOrderNum(modelList);
        // 循环遍历题目信息
        for (QuestionImportModel questionModel : modelList) {
            errorMessageList = new ArrayList<>();
            verifyModelFormat(questionModel, errorMessageList);
            question = QuestionImportUtils.transformModelToEntity(questionModel);
            question.setImportOrderNum(questionModel.getOrderNum());
            // 非案例题
            if (SysConst.Flag.NO.getFlag().equals(question.getCaseFlag())) {
                if (caseQuestion != null) {
                    if (CollectionUtil.isEmpty(caseQuestion.getQuestionList())) {
                        errorMessageList.add("案例题格式有误");
                    }
                    caseQuestion = null;
                }
                questionList.add(question);
            } else {
                // 案例题校验
                if (QuestionTypeEnum.CASE.getCode().equals(question.getTypeCode())) {
                    caseQuestion = question;
                    question.setQuestionList(new ArrayList<>());
                    questionList.add(question);
                } else {
                    if (SysConst.Flag.IS.getFlag().equals(question.getCaseFlag())) {
                        if (caseQuestion == null) {
                            errorMessageList.add("案例题数量不一致");
                        } else {
                            caseQuestion.getQuestionList().add(question);
                        }
                    } else {
                        caseQuestion = null;
                        questionList.add(question);
                    }
                }
            }
            if (CollectionUtil.isNotEmpty(errorMessageList)) {
                errorList.add(new ExcelImportError<>(
                        errorMessageList,
                        questionModel,
                        courseName,
                        questionModel.getOrderNum()
                ));
            }
        }
        return questionList;
    }

    /**
     * 导入题目信息模型转化为题目实体类模型 并返回报错信息
     *
     * @param questionListMapBySheetName 题目列表
     * @return 题目列表根据科目名称分组
     */
    public static Map<String, List<QuestionReq>> convertGroupListImportMultipleGroup(Map<String, List<QuestionImportModel>> questionListMapBySheetName) {
        // 结果集准备
        Map<String, List<QuestionReq>> result = new LinkedHashMap<>();
        List<QuestionReq> questionList;

        // 错误信息列表
        List<ExcelImportError<QuestionImportModel>> errorList = new ArrayList<>();

        // 遍历导入得结果集
        for (Map.Entry<String, List<QuestionImportModel>> questionListMapBySheetNameEntry : questionListMapBySheetName.entrySet()) {
            questionList =
                    convertGroupListImportModelList(questionListMapBySheetNameEntry.getValue(), questionListMapBySheetNameEntry.getKey(), errorList);
            result.put(questionListMapBySheetNameEntry.getKey(), questionList);
        }
        // 又不符合格式的信息，抛出异常
        if (CollectionUtil.isNotEmpty(errorList)) {
            throw new GlobalErrorListException(errorList);
        }
        return result;
    }

    /**
     * 校验导入模型题目得格式
     *
     * @param questionModel    题目导入模型数据
     * @param errorMessageList 错误信息列表
     */
    private static void verifyModelFormat(QuestionImportModel questionModel, List<String> errorMessageList) {
        if (StrUtil.isBlank(questionModel.getTypeCode())) {
            errorMessageList.add("题目类型信息为空");
        }
        if (!QuestionTypeEnum.getCodeSet().contains(questionModel.getTypeCode())) {
            errorMessageList.add("题目类型信息不支持/错误");
        }
        if (ObjectUtil.isNull(questionModel.getCaseFlag())) {
            errorMessageList.add("是否为案例题信息为空");
        }
        if (StrUtil.isBlank(questionModel.getContent())) {
            errorMessageList.add("题目内容不能为空");
        }
        if (StrUtil.isBlank(questionModel.getAnswer())
                && !QuestionTypeEnum.CASE.getCode().equals(questionModel.getTypeCode())) {
            errorMessageList.add("答案不能为空");
        } else if (StrUtil.isNotBlank(questionModel.getAnswer())) {
            // 去掉答案的所有空行
            String answerContent = questionModel.getAnswer();
            if (QuestionTypeEnum.MULTIPLE.getCode().equals(questionModel.getTypeCode())) {
                questionModel.setAnswer(answerContent.replaceAll("\\s*", ""));
            } else {
                questionModel.setAnswer(answerContent.trim());
            }
            // 答案规则校验
            if (QuestionTypeEnum.SINGLE.getCode().equals(questionModel.getTypeCode())
                    || QuestionTypeEnum.MULTIPLE.getCode().equals(questionModel.getTypeCode())) {
                if (!questionModel.getAnswer().matches(QuestionFormatConst.CHOOSE_REGEX)) {
                    errorMessageList.add("答案格式错误");
                }
            }
            if (QuestionTypeEnum.JUDGE.getCode().equals(questionModel.getTypeCode())) {
                if (!questionModel.getAnswer().matches(QuestionFormatConst.JUDGE_REGEX)) {
                    errorMessageList.add("答案格式错误");
                }
            }
            if (QuestionTypeEnum.SINGLE.getCode().equals(questionModel.getTypeCode())
                    || QuestionTypeEnum.MULTIPLE.getCode().equals(questionModel.getTypeCode())
                    || QuestionTypeEnum.JUDGE.getCode().equals(questionModel.getTypeCode())) {
                questionModel.setAnswer(questionModel.getAnswer().toUpperCase());
            }
        }
        if (QuestionTypeEnum.CASE.getCode().equals(questionModel.getTypeCode())
                && !SysConst.Flag.IS.getFlag().equals(questionModel.getCaseFlag())) {
            errorMessageList.add("案例题材料格式不正确");
        }
        if (QuestionTypeEnum.SINGLE.getCode().equals(questionModel.getTypeCode())
                || QuestionTypeEnum.MULTIPLE.getCode().equals(questionModel.getTypeCode())) {
            if ((StrUtil.isBlank(questionModel.getOptionA()))
                    || (StrUtil.isBlank(questionModel.getOptionB())
                    && StrUtil.isNotBlank(questionModel.getOptionC()))
                    || (StrUtil.isBlank(questionModel.getOptionC())
                    && StrUtil.isNotBlank(questionModel.getOptionD()))
                    || (StrUtil.isBlank(questionModel.getOptionD())
                    && StrUtil.isNotBlank(questionModel.getOptionE()))) {
                errorMessageList.add("选项信息格式错误");
            }
        }
    }

    /**
     * 将导入的questionModel转化为 entity 实体类
     *
     * @param questionImportModel 题目导入模型
     * @return question Entity
     */
    public static QuestionReq transformModelToEntity(QuestionImportModel questionImportModel) {
        QuestionReq entity = BeanUtil.toBean(questionImportModel, QuestionReq.class);

        List<Option> optionList = new ArrayList<>();
        if (QuestionTypeEnum.SINGLE.getCode().equals(questionImportModel.getTypeCode())
                || QuestionTypeEnum.MULTIPLE.getCode().equals(questionImportModel.getTypeCode())) {
            if (StrUtil.isNotBlank(questionImportModel.getOptionA())) {
                optionList.add(new Option("A", questionImportModel.getOptionA().trim()));
            }
            if (StrUtil.isNotBlank(questionImportModel.getOptionB())) {
                optionList.add(new Option("B", questionImportModel.getOptionB().trim()));
            }
            if (StrUtil.isNotBlank(questionImportModel.getOptionC())) {
                optionList.add(new Option("C", questionImportModel.getOptionC().trim()));
            }
            if (StrUtil.isNotBlank(questionImportModel.getOptionD())) {
                optionList.add(new Option("D", questionImportModel.getOptionD().trim()));
            }
            if (StrUtil.isNotBlank(questionImportModel.getOptionE())) {
                optionList.add(new Option("E", questionImportModel.getOptionE().trim()));
            }
        } else if (QuestionTypeEnum.JUDGE.getCode().equals(questionImportModel.getTypeCode())) {
            optionList = QuestionImportConst.DEFAULT_JUDGE_OPTION_LIST;
        }
        entity.setOptionList(optionList);
        return entity;
    }

    /**
     * 将导入的entity实体类 转化为 questionModel
     *
     * @param questionList 题目导出
     * @return model
     */
    public static List<QuestionExportModel> transformEntityToModel(List<Question> questionList) {
        List<QuestionExportModel> questionExportModelList = BeanUtil.copyToList(questionList, QuestionExportModel.class);

        for (int i = 0; i < questionExportModelList.size(); i++) {
            Question question = questionList.get(i);
            QuestionExportModel questionExportModel = questionExportModelList.get(i);
            if (QuestionTypeEnum.JUDGE.getCode().equals(questionExportModel.getTypeCode())) {
                questionExportModel.setOptionA("正确");
                questionExportModel.setOptionB("错误");
            }else {
                List<Option> optionList = question.getOptionList();
                handleQuestionOption(optionList, questionExportModel);
            }
        }
        return questionExportModelList;
    }

    private static void handleQuestionOption(List<Option> optionList, QuestionExportModel questionExportModel) {
        if (CollectionUtil.isEmpty(optionList)) {
            return;
        }
        for (Option option : optionList) {
            String optionNum = option.getOption();
            String content = option.getContent();
            switch (optionNum) {
                case "A":
                    questionExportModel.setOptionA(content);
                    break;
                case "B":
                    questionExportModel.setOptionB(content);
                    break;
                case "C":
                    questionExportModel.setOptionC(content);
                    break;
                case "D":
                    questionExportModel.setOptionD(content);
                    break;
            }
        }

    }
}
